package GameControl;

import java.util.ArrayList;
import java.util.List;

import GUI.ConsolenGUI;
import Gamefield.Field;
import Gamefield.FieldPosition;
import Gamefield.Gamefield;
import Gamefield.Player;
import Gamefield.Players;
import Pieces.MoveDirections;
import Pieces.Piece;
import Pieces.PieceMovement;
import Pieces.PiecePlayerEnum;

public class GameControl {
	private Gamefield _gamefield = new Gamefield();
	private Players _players = new Players();
	private Player _curPlayer;
	private int _curMoves = 0;
	private ConsolenGUI _console = new ConsolenGUI();
	private ArrayList<String> _gameLog = new ArrayList<String>();
	private ArrayList<String> _saveData = new ArrayList<String>();
	
	public void StartNewGame() {
		_gamefield.setField(_gamefield.GetStandardPosition());
        _players.add(new Player(PiecePlayerEnum.White,true));
        _players.add(new Player(PiecePlayerEnum.Black,true));
        _curPlayer =  _players.next(null);
        List<PieceMovement> allPosibleMoves;

       do {
        	allPosibleMoves = _gamefield.getAllPossibleMoves(_curPlayer);
        	_console.printBoard(_gamefield);
        	_curPlayer = _players.next(_curPlayer);
        	System.out.println(_curPlayer.getPlayerCol() + "'s Turn:");
        	PieceMovement nextMove;
        	
        	if (_curPlayer.IsHuman()){
        		do {
        			nextMove = parseMoveStringToMovement(_console.GetNextMove(),_curPlayer);
        		} while(!isValidMove(nextMove));
         	} else {
        		nextMove = parseMoveStringToMovement(_curPlayer.computeNextMove(),_curPlayer);
        	}
        	
        	_gamefield = Gamefield.executeNextMove(_gamefield,nextMove);
        	_gameLog.add(nextMove.toString());
        	_curMoves++;
        } while (allPosibleMoves.size() == 0);
        
        _console.printBoard(_gamefield);
	}

	private boolean isValidMove(PieceMovement nextMove) {
		if(nextMove == null){
			return false;
		}
		
		System.out.println(nextMove.toString());
		Gamefield nextMoveField = new Gamefield(_gamefield);
		boolean noErrors = true;
		Field curField = null;
		Field tarField = null;
		boolean drop = nextMove.getPosFrom().isDrop();
	
		if(drop){
			if((nextMove.getPosTo().getRow() > 4 || nextMove.getPosTo().getRow() < 0) && (nextMove.getPosTo().getCol() > 3 || nextMove.getPosTo().getCol() < 0)){
				noErrors = false;
				System.out.println("ERROR: Start or Target out of range");
			}
			// Piece in Tray?
			if(!_gamefield.getTray(nextMove.getPlayer().getPlayerCol()).hasPiece(nextMove.getFig())){
				noErrors = false;
				System.out.println("ERROR: Drop with wrong piece (not in Tray)");
			}
		} else {
			if((nextMove.getPosFrom().getRow() > 4 || nextMove.getPosFrom().getRow() < 0) && (nextMove.getPosFrom().getCol() > 3 || nextMove.getPosFrom().getCol() < 0)
				&& (nextMove.getPosTo().getRow() > 4 || nextMove.getPosTo().getRow() < 0) && (nextMove.getPosTo().getCol() > 3 || nextMove.getPosTo().getCol() < 0)){
				noErrors = false;
				System.out.println("ERROR: Start or Target out of range");
			}
			curField = _gamefield.getField()[nextMove.getPosFrom().getRow()][nextMove.getPosFrom().getCol()];
			
			//Wrong startField
			if(curField == null || curField.getPiece() == null ){
				noErrors = false;
				System.out.println("ERROR: Wrong startField");
			
			//Piece on source field?
			} else if(curField.getPiece().getPiecename() != nextMove.getFig()){
				noErrors = false;
				System.out.println("ERROR: Said Piece not on source field ("+curField.getPiece().getPiecename()+ " <> " + nextMove.getFig()+")");
			}
		}
		
		if(noErrors && _gamefield.targetFieldInGamefield(nextMove.getPosTo())){
			tarField = _gamefield.getField()[nextMove.getPosTo().getRow()][nextMove.getPosTo().getCol()];
			System.out.println("ERROR: Target is not in gamefield");
		}
		
		//Target is not a field
		if(tarField == null){
			noErrors = false;
			System.out.println("ERROR: Target is not a field");
		} else if(nextMoveField != null){
			// if capture target field cannot be empty
			if(nextMove.isCapture()){
				if(drop){
					noErrors = false;
					System.out.println("ERROR: Capture with drop not allowed");
				}
				// piece has to be there
				if(tarField.getPiece() == null){
					noErrors = false;
					System.out.println("ERROR: Capture -> piece not there");
				}
			} else {
				//  piece has not to be there
				if(tarField.getPiece() != null){				
					noErrors = false;
					System.out.println("ERROR: No Capture -> piece already there");
				}
			}
		}
		
		if (noErrors){
			// Watch check on next move -> no need to watch if on current (king moves away)
			if(Gamefield.KingIsInCheck(Gamefield.executeNextMove(nextMoveField,nextMove),nextMove.getPlayer())){				
				noErrors = false;
				System.out.println("ERROR: King in CHECK");
			}

			//valid move -> check movement
			MoveDirections md = Gamefield.getDirection(nextMove.getPosFrom(),nextMove.getPosTo());
			if(!drop){
				if(!curField.getPiece().getPossibleMoves().contains(md)){
					noErrors = false;
					System.out.println("ERROR: Piece cannot move like that");
				} 
			}
			
			// Promotions only with Pawns
			if (nextMove.isPromotion()){
				if(curField.getPiece().getPiecename() != 'P' && curField.getPiece().getPiecename() != 'p'){
					noErrors = false;
					System.out.println("ERROR: Promotions only with Pawns");
				}
			}
		}
		
		return noErrors;
	}
	
	// example PB3B2x or RC4C3 or PB2B1!
	private PieceMovement parseMoveStringToMovement(String nextMove,Player p) {
		if(nextMove.equals("SAVE")){
			saveState();
	    	for (String str : _saveData) {
	    		System.out.println(str);
			}
			return null;
		} else if (nextMove.equals("LOG")){
			for (String str : _gameLog) {
				System.out.println(str);
			}
			return null;
		}
		
		boolean capture = false;
		boolean promotion = false;
		String drop = nextMove.charAt(1)+""+nextMove.charAt(2);
		PieceMovement pm = new PieceMovement();
		
		if(nextMove.contains("x")){
			capture = true;
		}
		
		if(nextMove.charAt(nextMove.length() - 1) == '!'){
			promotion = true;
		}
		
		if(drop.equals("DR")){
			pm.setPosFrom(new FieldPosition(true));
			pm.setPosTo(new FieldPosition(Integer.parseInt(nextMove.charAt(4)+""),getIntFromCol(nextMove.charAt(3))));
		} else {
			pm.setPosFrom(new FieldPosition(Integer.parseInt(nextMove.charAt(2)+""),getIntFromCol(nextMove.charAt(1))));
			pm.setPosTo(new FieldPosition(Integer.parseInt(nextMove.charAt(4)+""),getIntFromCol(nextMove.charAt(3))));
			pm.setMove(Gamefield.getDirection(pm.getPosFrom(),pm.getPosTo()));
		}		
		
		pm.setFig(nextMove.charAt(0));
		pm.setCapture(capture);
		pm.setPromotion(promotion);
		pm.setPlayer(p);
		return pm;
	}

	public void saveState(){
		_saveData.add(_curPlayer.toString() + " " + _curMoves);
		StringBuffer sb = new StringBuffer();
		for (Piece p : _gamefield.getAllPieces(PiecePlayerEnum.White)) {
			sb.append(p.getPiecename() + p.getPosRow() + p.getPosCol()  + "/t");
		}
		_saveData.add(sb.toString());
		sb.setLength(0);
		for (Piece p : _gamefield.getAllPieces(PiecePlayerEnum.Black)) {
			sb.append(p.getPiecename() + p.getPosRow() + p.getPosCol() + "/t");
		}
		_saveData.add(sb.toString());
	}

	private int getIntFromCol(char col){
		int colnumb = 3;
		if (col == 'A'){
			colnumb = 1; 
		} else if(col == 'B'){
			colnumb = 2;
		} else if(col == 'C'){
			colnumb = 3; 
		} else {
			colnumb = -1;
		}
		
		return colnumb;
	}
	
}
